﻿//==============================================================================
// File: PropertyMetadata.cs
// Created: 2010-05-10
// Author: Piotr Włodek
//==============================================================================
// This file is a part of MAMMOTH project.
// Copyright (C) 2010 AGH University of Science and Technology, Krakow.
// https://caribou.iisg.agh.edu.pl/trac/mammoth
//
// Mammoth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Mammoth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with WpfRcp. If not, see http://www.gnu.org/licenses/.
//==============================================================================

using System;

namespace WpfRcp.PropertyModel
{
    /// <summary>
    /// Represents <see cref="MetaProperty"/>'s additional metadata.
    /// </summary>
    [Serializable]
    public class PropertyMetadata
    {
        private AssociationSync m_AssociationSync;
        private string m_DisplayName;

        /// <summary>
        /// Initializes a new instance of a <see cref="PropertyMetadata"/> class.
        /// </summary>
        public PropertyMetadata() : this(PropertyOptions.Matchable | PropertyOptions.UIVisible)
        {
        }

        /// <summary>
        /// Initializes a new instance of a <see cref="PropertyMetadata"/> class.
        /// </summary>
        /// <param name="options">Options specific to the property.</param>
        public PropertyMetadata(PropertyOptions options)
        {
            Options = options;
        }

        /// <summary>
        /// Initializes a new instance of a <see cref="PropertyMetadata"/> class.
        /// </summary>
        /// <param name="sync">Synchronization object for the Many-To-Many and One-To-Many synchronization.</param>
        public PropertyMetadata(AssociationSync sync) : this()
        {
            AssociationSync = sync;
        }

        /// <summary>
        /// Initializes a new instance of a <see cref="PropertyMetadata"/> class.
        /// </summary>
        /// <param name="propertyChanged">Callback to be executed each time the value of a property changes.</param>
        public PropertyMetadata(PropertyChangedCallback propertyChanged) : this()
        {
            PropertyChanged = propertyChanged;
        }

        /// <summary>
        /// Initializes a new instance of a <see cref="PropertyMetadata"/> class.
        /// </summary>
        /// <param name="propertyChanged">Callback to be executed each time the
        /// value of a property changes.</param>
        /// <param name="coerceValue">Callback to be executed when a value of a
        /// property is about to be set and need to be coerced.</param>
        public PropertyMetadata(PropertyChangedCallback propertyChanged, CoerceValueCallback coerceValue) : this()
        {
            PropertyChanged = propertyChanged;
            CoerceValue = coerceValue;
        }

        /// <summary>
        /// Initializes a new instance of a <see cref="PropertyMetadata"/> class.
        /// </summary>
        /// <param name="propertyChanged">Callback to be executed each time the
        /// value of a property changes.</param>
        /// <param name="coerceValue">Callback to be executed when a value of a
        /// property is about to be set and need to be coerced.</param>
        /// <param name="options">Options specific to the property.</param>
        public PropertyMetadata(PropertyChangedCallback propertyChanged, CoerceValueCallback coerceValue, PropertyOptions options)
        {
            PropertyChanged = propertyChanged;
            CoerceValue = coerceValue;
            Options = options;
        }
        
        /// <summary>
        /// Gets or sets default value.
        /// </summary>
        public object DefaultValue { get; set; }

        /// <summary>
        /// Gets or sets a default value callback.
        /// </summary>
        public Func<object> DefaultValueCallback { get; set; }

        /// <summary>
        /// Gets or sets a display name for a property.
        /// </summary>
        public string DisplayName
        {
            get { return DisplayNameCallback != null ? DisplayNameCallback() : m_DisplayName; }
            set { m_DisplayName = value; }
        }

        /// <summary>
        /// Gets or sets a display name callback for a property.
        /// </summary>
        /// <remarks>Use this property when you want your display
        /// name to be update when UI culture changes.</remarks>
        public Func<string> DisplayNameCallback { private get; set; }

        /// <summary>
        /// Gets various options for the property.
        /// </summary>
        private PropertyOptions Options { get; set; }

        /// <summary>
        /// Gets or sets <see cref="AssociationSync"/> object. This property can only be set once.
        /// </summary>
        public AssociationSync AssociationSync
        {
            get { return m_AssociationSync; }
            set
            {
                if (m_AssociationSync != null)
                    throw new InvalidOperationException();

                m_AssociationSync = value;
            }
        }

        /// <summary>
        /// Gets or sets a <see cref="PropertyChangedCallback"/> instance.
        /// </summary>
        internal PropertyChangedCallback PropertyChanged { get; private set; }

        /// <summary>
        /// Gets or sets a <see cref="CoerceValueCallback"/> instance.
        /// </summary>
        internal CoerceValueCallback CoerceValue { get; private set; }

        /// <summary>
        /// Checks if the given options are present in the metadata.
        /// </summary>
        /// <param name="options">Options that the check is being done against.</param>
        /// <returns>True if all given options are present. False otherwise.</returns>
        public bool ContainsOption(PropertyOptions options)
        {
            return ((Options & options) == options);
        }
    }
}